package com.eurake.seckill.controller;

import com.eurake.seckill.Exception.GlobalException;
import com.eurake.seckill.pojo.Order;
import com.eurake.seckill.vo.SeckillMessage;
import com.eurake.seckill.pojo.SeckillOrders;
import com.eurake.seckill.pojo.User;
import com.eurake.seckill.rabbitmq.MQSender;
import com.eurake.seckill.service.IGoodsService;
import com.eurake.seckill.service.IOrderService;
import com.eurake.seckill.service.ISeckillGoodsService;
import com.eurake.seckill.service.ISeckillOrdersService;
import com.eurake.seckill.utils.JSONUtil;
import com.eurake.seckill.vo.*;
import com.wf.captcha.ArithmeticCaptcha;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

//qps:2000
//优化后：最优qps：13000（全部重复购买）一般情况：3600（5w用户同时抢购5k个商品）最坏情况：900（商品还没卖完的时候）
@Controller
@RequestMapping("/seckill")
@Slf4j
public class seckillController implements InitializingBean {
    @Resource
    ISeckillOrdersService seckillOrdersService;

    @Resource
    ISeckillGoodsService seckillGoodsService;

    @Resource
    IOrderService orderService;

    @Resource
    IGoodsService goodsService;

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    MQSender mqSender;

    @Resource
    RedisScript<Long> redisScript;

    private Map<Long,Boolean> EmptyStockMap = new HashMap<Long,Boolean>();

    @RequestMapping("/doSeckill2")
    public String doSeckill2(Model model, User user,long goodsId) {
        if(user == null) {
            return "redirect:/login";
        }
        model.addAttribute("user",user);
        //获取秒杀货物库存
        GoodsVo goodsVo = seckillGoodsService.findGoodsVoByGoodsId(goodsId);
        //库存不够
        if(goodsVo.getGoodsStock()<=0){
            model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
            System.out.println("库存不够！");
            return "seckillFail";
        }
        List<SeckillOrdersVo> seckillOrderVo = seckillOrdersService.findOrderByUserIdAndGoodsId(user.getId(),goodsVo.getId());
        //重复购买
        if(seckillOrderVo.size()>0){
            model.addAttribute("errmsg", RespBeanEnum.REPEATE_ERROR.getMessage());
            System.out.println("重复购买！");
            return "seckillFail";
        }
        //获取秒杀货物
        Order order = orderService.seckill(user,goodsVo);

        model.addAttribute("order",order);
        model.addAttribute("goods",goodsVo);

        return "orderDetail";
    }

    @RequestMapping(value="/{path}/doSeckill",method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill(@PathVariable String path, User user, long goodsId) {
//        DetailVo detailVo = new DetailVo();
        if(user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
//        //库存不够
//        if(goodsVo.getStockCount()<1){
//            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
//        }
        ValueOperations valueOperations = redisTemplate.opsForValue();
        boolean check = orderService.checkPath(path,user,goodsId);
        if(check){
            return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
        }
        //判断是否重复抢购
        SeckillOrders seckillOrders = (SeckillOrders) valueOperations.get("order:"+user.getId()+":"+goodsId);
        if(seckillOrders!=null){
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        //内存标记减少redis的访问
        if(EmptyStockMap.get(goodsId)){
            return RespBean.error(RespBeanEnum.EMPTY_STOCK );
        }
        //预减库存,第一种方式
        Long stock = (Long)redisTemplate.execute(redisScript, Collections.singletonList("seckillGoods:"+goodsId),Collections.EMPTY_LIST);
        // 第二种方式：       Long stock = valueOperations.decrement("seckillGoods:"+goodsId);
        if(stock<0){
            EmptyStockMap.put(goodsId,true);
        // 第二种方式           valueOperations.increment("seckillGoods:"+goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK );
        }
        SeckillMessage seckillMessage = new SeckillMessage();
        seckillMessage.setGoodsId(goodsId);
        seckillMessage.setUser(user);
        mqSender.sendSeckillMsg(JSONUtil.object2JsonStr(seckillMessage));
        //获取秒杀货物的id
//        GoodsVo goodsVo = seckillGoodsService.findGoodsVoByGoodsId(goodsId);
//        Order order = orderService.seckill(user,goodsVo);
//        if(order==null){
//            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
//        }
        return RespBean.success(0);

//         List<SeckillOrdersVo> seckillOrderVo = seckillOrdersService.findOrderByUserIdAndGoodsId(user.getId(),goodsVo.getId());
        //重复购买
//        if(seckillOrderVo.size()>0){
//            System.out.println("重复购买！");
//            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
//        }

/*        Order order = orderService.seckill(user,goodsVo);
        if(order==null){
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }

        detailVo.setUser(user);
        detailVo.setGoods(goodsVo);
        detailVo.setOrder(order);*/

//        return RespBean.success(detailVo);
    }

    //存在非0的goodsId即为成功，0为排队中，-1为秒杀失败
    @RequestMapping(value = "/result",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getResult(User user,Long goodsId) {
        if(user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Long orderId =  seckillOrdersService.getResult(user,goodsId);
        return RespBean.success(orderId);
    }

    @RequestMapping(value = "/path",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getPath(User user,Long goodsId) {
        if(user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);
        Date startTime = goodsVo.getStartDate();
        Date endTime = goodsVo.getEndDate();
        Date now = new Date();
        if(now.before(startTime)){
            //秒杀未开始
            return RespBean.success();
        }
        String str = orderService.createPath(user,goodsId);
        return RespBean.success(str);
    }

    @RequestMapping(path = "/captcha", method = RequestMethod.GET)
    public void verifyCode(User user, Long goodsId, HttpServletResponse response) {
        if (user == null || goodsId < 0) {
            throw new GlobalException(RespBeanEnum.REQUEST_ILLEGAL);
        }
        // 设置请求头类型
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
        log.info("ok");
        redisTemplate.opsForValue().set("captcha:" + user.getId() + ":" + goodsId, captcha.text(), 300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        } catch (IOException e) {
            log.error("验证码生成失效", e.getMessage());
        }
    }

    //系统初始化时执行的方法
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> list = goodsService.findGoodsVo();
        if(CollectionUtils.isEmpty(list)){
            return ;
        }
        list.forEach(goodsVo -> {
            redisTemplate.opsForValue().set("seckillGoods:"+goodsVo.getId(),goodsVo.getStockCount());
            EmptyStockMap.put(goodsVo.getId(),false);
        });
    }
}
